package com.parkLot.spring.service.impl;

import com.mingke.Domain.BillEntity;
import com.mingke.Domain.ParkEntity;
import com.mingke.Domain.ParkPointEntity;
import com.mingke.TransformObject.PointSwitchTO;
import com.mingke.Utils.BillStatuConstant;
import com.mingke.Utils.PageUtils;
import com.mingke.Utils.Query;
import com.mingke.ViewObject.ParkPointViewObject;
import com.parkLot.spring.dao.ParkPointDao;
import com.parkLot.spring.service.BillService;
import com.parkLot.spring.service.ParkPointService;
import com.parkLot.spring.service.ParkService;
import com.parkLot.spring.socket.SocketServerPoint;
import com.parkLot.spring.socket.SocketServerPointHex;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.util.StringUtils;


@Service("parkPointService")
public class ParkPointServiceImpl extends ServiceImpl<ParkPointDao, ParkPointEntity> implements ParkPointService {

    @Autowired
    private ParkService parkService;

    @Autowired
    private BillService billService;

    @Autowired
    private SocketServerPointHex socketServer;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        //ParkPointEntity
        String key = (String) params.get("key");
        QueryWrapper<ParkPointEntity> wrapper = new QueryWrapper<>();
        if(!StringUtils.isEmpty(key)) {
            wrapper.like("parkPoint_address", key);
        }
        IPage<ParkPointEntity> page = this.page(
                new Query<ParkPointEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }

    @Override
    public List<ParkPointViewObject> getPointByParkLotId(Integer pid) {
        QueryWrapper<ParkPointEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("park_id", pid);
        List<ParkPointEntity> list = list(wrapper);
        QueryWrapper<BillEntity> wrapper1 = new QueryWrapper<>();
        wrapper1.eq("bill_statu", BillStatuConstant.PARKING.getCode());
        List<BillEntity> bills = billService.list(wrapper1);
        List<ParkPointViewObject> vos = new ArrayList<>();
        for(ParkPointEntity point : list){
            ParkPointViewObject vo = new ParkPointViewObject();
            BeanUtils.copyProperties(point, vo);
            vo.setCustomerId(0);
            //对于使用中的节点进行配置
            if(point.getParkPointStatus()==102){
                for(BillEntity billEntity : bills){
                    if(billEntity.getBillParkingId() == point.getParkPointId()){
                        //如果节点的id和账单的节点id对上了，就设置上
                        vo.setCustomerId(billEntity.getBillCustomerId());
                    }
                }
            }
            vos.add(vo);
        }
        return vos;
    }

    @Override
    public boolean savePoint(ParkPointEntity parkPoint) {
        //保存一个新的节点信息
        boolean saveResult = save(parkPoint);
        //对应的停车场的可用车位也要发生变化
        ParkEntity parkEntity = parkService.getById(parkPoint.getParkId());
        parkEntity.setParkTotle(parkEntity.getParkTotle() + 1);
        boolean updateResult = parkService.updateById(parkEntity);
        return (saveResult && updateResult);
    }

    @Override
    public boolean updatePoint(ParkPointEntity parkPoint) {
        //updateById(parkPoint);
        ParkPointEntity afterParkPoint = getById(parkPoint.getParkPointId());
        ParkEntity parkEntity = parkService.getById(parkPoint.getParkId());
        if(parkPoint.getParkPointStatus()==102){
            //此时要更改状态为开启，如果原先为闲置，则需要修改
            if(afterParkPoint.getParkPointStatus()==101){
                parkEntity.setParkInUse(parkEntity.getParkInUse()+1);
            }
        }
        if(parkPoint.getParkPointStatus()==101){
            //此时要更改状态为闲置，如果原先为使用，则需要修改
            if(afterParkPoint.getParkPointStatus()==102){
                parkEntity.setParkInUse(parkEntity.getParkInUse()-1);
            }
        }
        boolean pointResult = updateById(parkPoint);
        boolean parkResult = parkService.updateById(parkEntity);
        return (pointResult && parkResult);
    }

    @Override
    public boolean switchPointUseStatu(PointSwitchTO to) {
        ParkPointEntity parkPointEntity = getById(to.getPointId());
        parkPointEntity.setParkPointStatus(to.getSwitchStatu());
        //TODO 需要完成用户账单的相关操作，开始计时
        if(to.getSwitchStatu() == 102){
            //发送102说明要使用节点，需要创建一个新的订单
            BillEntity billEntity = buildBillEntity(to);
            billService.save(billEntity);
            //TODO 开始使用车位，降下地锁
            String address = parkPointEntity.getParkPointAddress().split("x")[1];
            startPoint(Integer.parseInt(address));
        }else {
            //发送101说明车辆离开，需要修改订单状态和订单结束时间
            QueryWrapper<BillEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("bill_parking_id", to.getPointId());
            queryWrapper.eq("bill_customer_id", to.getUid());
            queryWrapper.eq("bill_statu", BillStatuConstant.PARKING.getCode());
            BillEntity billEntity = billService.getOne(queryWrapper);
            if(billEntity != null){
                billEntity.setBillEnd(new Date());
                billEntity.setBillStatu(BillStatuConstant.UNPAY.getCode());
                billService.updateById(billEntity);
            }
            //TODO 用户点击离开，地锁打开
            String address = parkPointEntity.getParkPointAddress().split("x")[1];
            stopPoint(Integer.parseInt(address));
        }

        return updatePoint(parkPointEntity);
    }

    @Override
    public boolean startPoint(Integer id) {
        String info = "2f"+String.format("%02x", id);
        System.out.println("发送的信息："+info);
        socketServer.sendToESP8266(info);
        return true;
    }

    @Override
    public boolean stopPoint(Integer id) {
        String info = "2e"+String.format("%02x", id);
        System.out.println("发送的信息："+info);
        socketServer.sendToESP8266(info);
        return true;
    }

    @Override
    public boolean queryPoint(Integer id) {
        String info = "2d"+String.format("%02x", id);
        System.out.println("发送的信息："+info);
        socketServer.sendToESP8266(info);
        return true;
    }

    @Override
    public boolean errorPoint(Integer id) {
        String info = "2a"+String.format("%02x", id);
        System.out.println("发送的信息："+info);
        socketServer.sendToESP8266(info);
        return true;
    }

    @Override
    public boolean getPointByAddress(String address) {
        QueryWrapper<ParkPointEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("park_point_address", address);
        ParkPointEntity parkPointEntity = this.getOne(wrapper);
        QueryWrapper<BillEntity> billWrapper = new QueryWrapper<>();
        billWrapper.eq("bill_statu", BillStatuConstant.PARKING.getCode());
        billWrapper.eq("bill_parking_id", parkPointEntity.getParkPointId());
        BillEntity billEntity = billService.getOne(billWrapper);
        if(billEntity==null){
            //没有车辆使用车位
            log.warn("车位未使用");
            return false;
        }
        if(findBetweenTime(billEntity.getBillStart())){
            //改变订单状态
            billEntity.setBillStatu(BillStatuConstant.UNPAY.getCode());
            billEntity.setBillEnd(new Date());
            billService.updateById(billEntity);
            //修改节点状态，并且给下位机发送指令
            Integer uid = billEntity.getBillCustomerId();
            PointSwitchTO to = new PointSwitchTO();
            to.setUid(uid);
            to.setPointId(parkPointEntity.getParkPointId());
            to.setSwitchStatu(101);
            return switchPointUseStatu(to);
        }else {
            return false;
        }
    }

    private boolean findBetweenTime(Date start) {
        Date now = new Date();
        long between = now.getTime() - start.getTime();
        long day = between / (24 * 60 * 60 * 1000);
        long hour = (between / (60 * 60 * 1000) - day * 24);
        long min = ((between / (60 * 1000)) - day * 24 * 60 - hour * 60);
        long s = (between / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
        //如果时间间隔没超过十秒，那就是车主开启车位后还没来得及使用
        //这时候就先不管车位感应
        //如果超过了，说明是车离开车位，此时发送命令让地锁升起来
        log.warn("总共用时："+s+"秒");
        if(s > 10){
            log.warn("车辆使用完毕，开启地锁");
            return true;
        }else {
            log.warn("车辆还没入场， 不要开地锁");
            return false;
        }
    }

    public BillEntity buildBillEntity(PointSwitchTO to){
        BillEntity billEntity = new BillEntity();
        ParkPointEntity parkPointEntity = getById(to.getPointId());
        //ParkEntity parkEntity = parkService.getById(parkPointEntity.getParkId());
        billEntity.setBillStatu(BillStatuConstant.PARKING.getCode());
        billEntity.setAddTime(new Date());
        billEntity.setBillCustomerId(to.getUid());
        billEntity.setBillParkingId(parkPointEntity.getParkPointId());
        billEntity.setBillStart(new Date());
        billEntity.setUpdateTime(new Date());
        return billEntity;
    }

}